// type_info wrapper from Alexandrescu Loki library
#ifndef LOKI_LOKITYPEINFO_INC_
#define LOKI_LOKITYPEINFO_INC_

#include <typeinfo>
#include <cassert>

namespace utils
{
    ////////////////////////////////////////////////////////////////////////////////
    // class type_info_t
    // Purpose: offer a first-class, comparable wrapper over std::type_info
    ////////////////////////////////////////////////////////////////////////////////

    class type_info_t
    {
    public:
        // Constructors
        type_info_t(); // needed for containers
        type_info_t(const std::type_info&); // non-explicit

        // Access for the wrapped std::type_info
        const std::type_info& Get() const;
        // Compatibility functions
        bool before(const type_info_t& rhs) const;
        const char* name() const;

    private:
        const std::type_info* pInfo_;
    };
    
    // Implementation

    inline type_info_t::type_info_t()
    {
        class Nil
        {
        };
        pInfo_ = &typeid(Nil);
        assert(pInfo_);
    }
    
    inline type_info_t::type_info_t(const std::type_info& ti) :
        pInfo_(&ti)
    {
        assert(pInfo_);
    }
    
    inline bool type_info_t::before(const type_info_t& rhs) const
    {
        assert(pInfo_);
        // type_info::before return type is int in some VC libraries 
        return pInfo_->before(*rhs.pInfo_) != 0;
    }

    inline const std::type_info& type_info_t::Get() const
    {
        assert(pInfo_);
        return *pInfo_;
    }
    
    inline const char* type_info_t::name() const
    {
        assert(pInfo_);
        return pInfo_->name();
    }

    // Comparison operators

    inline bool operator==(const type_info_t& lhs, const type_info_t& rhs)
    // type_info::operator== return type is int in some VC libraries
    {
        return (lhs.Get() == rhs.Get()) != 0;
    }

    inline bool operator<(const type_info_t& lhs, const type_info_t& rhs)
    {
        return lhs.before(rhs);
    }

    inline bool operator!=(const type_info_t& lhs, const type_info_t& rhs)
    {
        return !(lhs == rhs);
    }
    
    inline bool operator>(const type_info_t& lhs, const type_info_t& rhs)
    {
        return rhs < lhs;
    }
    
    inline bool operator<=(const type_info_t& lhs, const type_info_t& rhs)
    {
        return !(lhs > rhs);
    }

    inline bool operator>=(const type_info_t& lhs, const type_info_t& rhs)
    {
        return !(lhs < rhs);
    }
}

#endif // end file guardian
